Глубокое и поверхностное тестирование, часть 2: "поверхностное" – это фича, а не оскорбление! |
26.07.2022 00:00 |
Автор: Майкл Болтон (Michael Bolton) Когда мы говорим о глубоком и поверхностном тестировании в терминологии Rapid Software Testing, многие полагают, что "глубокое" тестирование – это хорошо, почетно и правильно, а "поверхностное" – оскорбление. Но это не так. "Поверхностное" – это не оскорбление. Глубина и поверхностность – это способы обсудить тщательность тестирования, но они не оценивают его ценность. Ценность, качество, уместность тщательности можно оценивать только в контексте. Поверхностное тестирование может быть идеальным вариантом для определенных задач, а глубокое – патологическим. Как так? Начнем с объяснений, что же мы на самом деле имеем в виду. Поверхностное тестирование – это тестирование, которое с шансами найдет все простые баги "Поверхностное тестирование" – это не оскорбление! Поверхностное – не значит небрежное, и не значит халтурное. И поверхностное тестирование, и поиск простых багов – это хорошие штуки. Мы хотим найти баги – особенно простые – как можно быстрее и эффективнее, и у поверхностного тестирования есть шанс их найти. Поверхностное тестирование в какой-то мере помогает покрытию, особенно в отдельных областях продукта. Во множестве контекстов поверхностность тестирования – это фича, а не баг. Вот вам форма поверхностного тестирования: проверки в духе TDD. Когда разработчики проектируют и внедряют TDD-проверки, у них нет цели глубоко протестировать продукт. Цель – эффективно и постепенно продвигаться в построении функции или характеристики. Каждая новая проверка быстро информирует, что новый код делает именно то, чего хотел программист. Перезапуск существующего набора проверок дает разработчику некоторую долю уверенности в том, что новый код не привнес легких в обнаружении проблем. TDD позволяет быстрый прогресс, концентрируя программиста на экспериментах с дизайном и эффективном создании кода. Эти усилия поддерживаются простыми, быстрыми проверками первого порядка. Это отличный, оправданный и ответственный подход к созданию новой фичи. Когда я пишу код, я не хочу проводить сложные, длительные, тщательные эксперименты, изучающие множество различных областей покрытия, каждый раз, когда я меняю чертов код. Вы тоже не хотите. TDD-проверки обычно не проверяют безопасность, удобство использования, производительность, совместимость и устанавливаемость. Если бы они это делали, то стали бы невыносимо медленными и тяжеловесными, а их запуск занимал бы кучу времени. Проверки такого рода уместно и ответственно быстрые, дешевые и достаточно тщательные, и позволяют разработчикам надежно двигаться вперед, не слишком отрывая их от работы. Идея тут в поиске простых багов в очистном забое, прилагая относительно небольшие усилия, дающие максимальную выгоду. Эта скорость и простота – абсолютно точно фича поверхностного тестирования! Не баг! Поверхностное тестирование – это также то, чем тестировщики должны заниматься на ранних стадиях знакомства с продуктом, потому что способа телепортировать тестировщика с разгона в глубокое тестирование не существует. Разработчик создает свои ментальные модели продукта в ходе его создания. У тестировщика нет этой инсайдерской информационной картины создателя. Отсутствие этой картины – как фича, так и баг. Это фича, так как тестировщик смотрит на продукт свежим взглядом, и это полезно для идентификации проблем и рисков. Это баг, потому что тестировщику нужно пройти через стадии обучения, необходимой путаницы и самонастройки, чтобы изучить продукт. Предположение о самонастройке гласит, что любой процесс, рано или поздно становящийся хорошими эффективным, начинал как плохой и неэффективный; любой процесс, сконцентрированный на том, чтобы сделать все правильно с первого раза, будет успешным только тогда, когда он тривиален, или же просто повезло. При первых встречах с продуктом тестировщик проводит поверхностное тестирование – тестирование, которое с шансами найдет все простые баги. Это дает возможность изучить продукт, избавляя тестировщика от обязанности слишком рано перейти к глубокому тестированию. Так что же такое глубокое тестирование? Глубокое тестирование – это тестирование, максимизирующее шансы найти все трудодноуловимые значимые баги Это нуждается в некоторых объяснениях. Для начала разберемся с "максимизирующим". Никакое тестирование, никакая его форма не гарантирует, что мы найдем все баги (заметьте, что в Rapid Software Testing баг – это что угодно в продукте, угрожающее его ценности в глазах лица, чье мнение важно). Распространенная максима звучит как "полное тестирование невозможно": мы не можем ввести все возможные варианты ввода, исследовать все возможные варианты вывода, выполнить все функции в продукте в любой возможной последовательности с любой возможной вариацией по времени, на любой возможной платформе и состоянии машины, которое мы все равно не можем полностью контролировать. Учитывая, что мы имеем дело с бесконечным, непокорным, многомерным тест-пространством, навыки тестирования имеют значение, но некоторая удача неминуемо сыграет свою роль. Мы можем только стараться максимизировать наши шансы на нахождение багов, потому что баги до какой-то степени трудоноуловимы. Баги могут быть едва различимыми, скрытыми, редкими, плавающими или внезапно возникающими. Некоторые баги едва различимы из-за плохо понятых аспектов языков программирования или неожиданного поведения технологий. Некоторые баги скрыты в сложном, неясном или старом коде. Некоторые баги спрятаны в коде, который писали не мы, но мы вызываем его в библиотеке, фреймворке или операционной системе. Некоторые баги редки, возникают в зависимости определенных сочетаний необычных условий или вызова кода, столкнувшегося с определенными данными, или существуют только на отдельных платформах. Некоторые баги плавают, проявляясь нечасто, когда система находится в определенном состоянии. И, возможно, самое важное – некоторые баги возникают внезапно. Все компоненты продукта могут отлично работать сами по себе, но в системе возникают проблемы, когда эти элементы комбинируются. Общая библиотека, разработанная изнутри, поддерживающая один из продуктов, может мешать функциям другого. Продукт, который отлично выглядит в одном браузере, может не поладить с другим внедрением стандартов в другом браузере. Я только сегодня получил письмо от друга, использующего Mac, которое, уверен, прекрасно выглядело на его машине, однако в Windows Outlook оно отображалось неверно. Продукт, хорошо работающий в лаборатории, может столкнуться со странными проблемами тайминга, когда в игру вступает качество сети, или когда множество людей одновременно пользуются системой. Время тоже может быть фактором. Классический случай – проблема-2000; хранение компонента года даты в двузначном поле не было особой проблемой в 1970, когда хранение было дорогим и люди не предвидели, что системой могут все еще пользоваться поколение спустя. Программы, отлично работавшие на однозадачных 8086-процессорах столкнулись с проблемами, запускаясь на 80386 процессорах в предположительно совместимом виртуальном 8086-режиме. (Это повсюду. Пока я писал статью, наткнулся на какой-то латентный баг на своем сайте, который проявляется только при попытке обновить PHP – возможно, это связано с более тщательными проверками в новом PHP-интерпретаторе. Это не было проблемой при создании сайта много лет назад, а теперь я не могу обновиться, не разобравшись. Эх.) Трудноуловимые баги могут скрыться даже от очень дисциплинированного процесса разработки, а также от глубокого тестирования. Повторюсь – гарантий никто не даст, но идея глубокого тестирования в максимизации шансов на нахождение трудноуловимых багов. Как узнать, что баг трудноуловим или был таким? Когда трудноуловимый баг находится в разработке, до релиза, опытные члены команды скажут что-то вроде "Ого! Это было бы очень трудно заметить. Как хорошо, что ты его нашел". Когда баг в продукте объявляется на проде, то он по определению скрылся от нас, но был ли он трудноуловимым? Трудноуловимость – это не свойство бага, это социальная оценка – взаимоотношения между багом, людьми и контекстом. Если баг прода был трудноуловимым, наша социальная группа согласится с этим, "Возможно, мы бы это и нашли, но это было бы очень, очень трудно". Если баг таким не был, наша социальная группа скажет "Учитывая доступные нам время и ресурсы, мы должны были это выловить". В любом случае ответственные люди скажут "Этот баг может нас чему-то научить". Из этого совершенно верно следует, что и трудноуловимость, и глубина субъективные социальные конструкты. Баг, который легко найдет разработчик – поверхностный с его точки зрения – может глубоко зарыться к моменту, когда он перейдет к тестировщику. Когда баг похоронен под слоями кода, и его сложно добыть с поверхности продукта, намеренный поиск этого бага требует глубокого тестирования. Тестировщик, способный анализировать и моделировать риски, и писать код для генерации богатых тестовых данных, с большими шансами найдет глубокие, более трудноуловимые связанные с данными баги, чем тестировщик, которому не хватает таких навыков. Баг, простой для доменного эксперта, легко ускользнет от того, кто в вопросе не разбирается. Опыт разработки в домене продукта – это элемент глубокого тестирования. Тестировщик с богатым, разнообразным набором моделей покрытия продукта может найти легкие, со своей точки зрения, баги, но разработчик без соответствующих моделей сочтет это глубинным багом. В целом глубокое тестирование куда более затратно по финансам и времени, чем поверхностное. Поэтому мы и не хотим заниматься им
Возможно, нам не нужно проводить глубокое тестирование, если мы уже достаточно им занимались, и хотим только проверить статус билда перед релизом. Возможно, нам не нужно глубокое тестирование, если изменение небольшое, простое, хорошо изолированное, а само изменение и его эффекты тщательно проверены. Такое тестирование будет обсессивно-компульсивным, патологически глубоким. Итак, повторюсь, вопрос не в том, что поверхностное – это плохо, а глубокое – хорошо. В некоторых контекстах поверхностное – это именно то, что нужно, а глубокое будет уже чересчур дорогим и бессмысленным. Ключ для понимания – это контекст и разрыв риска: разрыв между тем, что мы уверенно знаем, и тем, что нам нужно знать, чтобы принимать качественные решения о продукте. |